---
layout: none
---
{%

assign version = site.data.info.version %}{%

capture download_url
  %}https://github.com/rsms/raster/releases/download/v{{ version }}/Raster-v{{ version }}.zip{%
endcapture %}{%

for file in site.static_files %}{%
  assign _path = file.path | remove_first: "/raster" %}{%
  if _path == "/res/base.css" %}{%
    assign base_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
  elsif _path == "/res/generate-grid.js" %}{%
    assign generate_grid_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
  endif %}{%
endfor

%}<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Raster—CSS Grid System</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <link rel="stylesheet" href="raster2.css?v={{version}}">
  <script src="raster2.js?v={{version}}"></script>
  <link rel="stylesheet" href="res/base.css?v={{base_css_v}}">
</head>
<body>
  <r-grid columns="8">
    <r-cell span="2" span-s="row">
      <h1>
        Raster<br>
        Simple Grid System
      </h1>
      <br>
      <p>
        Minimal and straight-forward CSS grid system
        utilizing descriptive HTML rather than semantic CSS.
      </p>
      <r-grid columns=2>
        <r-cell><a class="download-button" href="{{download_url}}">
          Download &darr;
        </a></r-cell>
        <r-cell class="center flex-v">
          <a href="examples/">Examples</a>
        </r-cell>
      </r-grid>
      <br>
    </r-cell>
    <r-cell span="3.." span-s="row">
      <r-grid columns=8 class="demo">
        <r-cell>1</r-cell> <r-cell>2</r-cell> <r-cell>3</r-cell> <r-cell>4</r-cell> <r-cell>5</r-cell> <r-cell>6</r-cell> <r-cell>7</r-cell> <r-cell>8</r-cell>

        <r-cell></r-cell>
        <r-cell span=3>3</r-cell>
        <r-cell></r-cell>
        <r-cell span=7-8>7-8</r-cell>
        <r-cell span=2+2>2+2</r-cell>
        <r-cell span=5-8>5-8</r-cell>
        <r-cell span=1-4>1-4</r-cell>
        <r-cell span=6..>6..</r-cell>
        <r-cell span=2..>2..</r-cell>
        <r-cell span=4..>4..</r-cell>
        <r-cell span=1-2>1-2</r-cell>
        <r-cell span=4-5>4-5</r-cell>
      </r-grid>
      <br><br>
    </r-cell>

    <r-cell span="3.." span-s=row class="h2">
      Simplicity first
    </r-cell>

    <r-cell span="1-2" span-s="row">
      <pre class="side-sample">&lt;r-grid columns=8&gt;
  &lt;r-cell&gt;&lt;/r-cell&gt;
  &lt;r-cell span=3&gt;3&lt;/r-cell&gt;
  &lt;r-cell&gt;&lt;/r-cell&gt;
  &lt;r-cell span=7-8&gt;7-8&lt;/r-cell&gt;
  &lt;r-cell span=2+2&gt;2+2&lt;/r-cell&gt;
  &lt;r-cell span=5-8&gt;5-8&lt;/r-cell&gt;
  &lt;r-cell span=1-4&gt;1-4&lt;/r-cell&gt;
  &lt;r-cell span=6..&gt;6..&lt;/r-cell&gt;
  &lt;r-cell span=2..&gt;2..&lt;/r-cell&gt;
  &lt;r-cell span=4..&gt;4..&lt;/r-cell&gt;
  &lt;r-cell span=1-2&gt;1-2&lt;/r-cell&gt;
  &lt;r-cell span=4-5&gt;4-5&lt;/r-cell&gt;
&lt;/r-grid&gt;</pre>
    </r-cell>

    <r-cell span="3-6" span-s="row">
      <p>
        The number of columns a grid has is specified by the
        <code>columns</code> attribute.
        For instance, to define a grid with 8 columns, you'd write
        <code>&lt;r-grid columns=8&gt;</code>.
      </p>
      <p>
        Cells span a single column by default.
        The <code>span</code> attribute is used to customize where a cell
        starts and how many columns it spans.
        For example, <code>&lt;r-cell span=2-5&gt;</code> starts in column 2 and ends in column 5.
        A cell with an empty or missing <code>span</code> attribute starts on
        the next available column and spans one column.
      </p>
      <p>
        Raster is <a href="raster2.css?v={{version}}">pure CSS</a> — no JavaScript involved.
      </p>
      <p>
        The HTML here is what generates the grid you see at the top of this page.
      </p>
      <p>
        <a href="examples/">More examples</a>
      </p>
    </r-cell>
    <r-cell span="7.." span-s="row">
      <h4>Possible span= values</h4><br>
      <p>
        <r-grid columns=8 style="column-gap:1.5rem">
          <r-cell><code>2-5</code></r-cell>
          <r-cell span=2..>start in column 2,<br>end in column 5.</r-cell>

          <r-cell><code>2+3</code></r-cell>
          <r-cell span=2..>start in column 2,<br>span 3 columns.</r-cell>

          <r-cell><code>2..</code></r-cell>
          <r-cell span=2..>start in column 2,<br>span remainder of row.</r-cell>

          <r-cell><code>2</code></r-cell>
          <r-cell span=2..>start in next column,<br>span 2 columns.</r-cell>

          <r-cell><code>row</code></r-cell>
          <r-cell span=2..>span a full row</r-cell>
        </r-grid>
      </p>
    </r-cell>

    <r-cell span=3.. class="ruler only-large-screen"></r-cell>

    <r-cell span=3.. span-s=row class="h2" id="responsive-design">
      Responsive design
    </r-cell>

    <r-cell span=1-2 span-s=row>
       <pre class="side-sample">&lt;r-grid columns=6&gt;
  &lt;r-cell span=2   <b>span-s=row</b>&gt;
  &lt;r-cell span=3-6 <b>span-s=row</b>&gt;
  &lt;r-cell span=1-2 <b>span-s=1</b>&gt;
  &lt;r-cell span=3.. <b>span-s=2..</b>&gt;
&lt;/r-grid&gt;</pre><br>
    </r-cell>
    <r-cell span=3-6 span-s=row>
      <p>
        Grids lend themselves really well to device-size responsive design.
        The <code>span-s</code> attribute defines alternate layout when your
        design is presented on a small screen.
        This makes designing for large and small screens really easy.
      </p>
      <r-grid columns=6 class="example" id="example1">
        <r-cell span=2 span-s=row class=black>Acme</r-cell>
        <r-cell span=3-6 span-s=row>Things &nbsp;&nbsp; About &nbsp;&nbsp; Privacy policy</r-cell>
        <r-cell span=1-2 span-s=1 class=black>Image</r-cell>
        <r-cell span=3.. span-s=2..>Welcome to Acme</r-cell>
      </r-grid>
      <p>
        Tap the example above—or resize your web browser window—to see the
        layout change.
        Showing <b id="example1-label1" class="example-label">large</b> screen.
        Additionally, the <code>span-l</code> attribute can be used to control
        an alternate layout for really large screens.
      </p>
      <p>
        This entire website is built with grids and changes layout when the
        window size passes 600dp.
      </p>
    </r-cell>

    <r-cell span=3.. span-s=row class="h3" id="responsive-design">
      Additional responsive control with columns-s
    </r-cell>

    <r-cell span=1-2 span-s=row>
       <pre class="side-sample">&lt;r-grid columns=6<br>      <b>columns-s=3</b>&gt;
  &lt;r-cell&gt;
  &lt;r-cell span=2&gt;
  &lt;r-cell&gt;
  &lt;r-cell span=2&gt;
&lt;/r-grid&gt;</pre><br>
    </r-cell>
    <r-cell span=3-6 span-s=row>
      <p>
        Similar to <code>span-s</code>, <code>columns-s</code> is available
        on <code>r-grid</code> tags for alternate layout on small screens.
        Often a small-screen layout can be accomplished by simply setting
        <code>columns-s</code> without the need for any <code>span-s</code>
        attributes. The <code>columns-l</code> attribute is also available
        for large screens.
      </p>
      <r-grid columns=6 columns-s=3 class="example" id="example2">
        <r-cell class=black>Foo</r-cell>
        <r-cell span=2>Description of foo</r-cell>
        <r-cell class=black>Bar</r-cell>
        <r-cell span=2>Description of bar</r-cell>
      </r-grid>
      <p>
        Tap the example above—or resize your web browser window—to see the
        layout change.
        Showing <b id="example2-label1" class="example-label">large</b> screen.
      </p>
    </r-cell>

    <r-cell span=3.. class="ruler only-large-screen"></r-cell>

    <r-cell span=3.. span-s=row class="h2" id="responsive-design">
      Excellent websites with minimal effort
    </r-cell>

    <r-cell span=1-2 span-s=row>
      <a href="examples/">Example gallery</a>
    </r-cell>

    <r-cell span=3-6 span-s=row>
      <p>
        Raster is a complete CSS framework for creating websites.<br>
        The Raster system is minimal but complete:
      </p>
      <ul>
        <li>
          Provides a simple, minimal and solid starting point for
          websites. Get started quickly with the
          <a href="template.html">HTML template</a>, or just include
          <a href="raster2.css?v={{version}}">raster2.css</a> in your own
          HTML.
        </li>
        <li>
          Grids as the foundation assists in creating graphically harmonious
          and expressive designs.
        </li>
        <li>
          Good typography and scale harmony out of the box.
        </li>
        <li>
          Easy customization via CSS variables.
          For instance, set <code>--fontSize: 18px</code> to change
          the entire scale of your website, or fine-tune spacing of various
          elements using the <code>--lineHeight</code> variable, which is the
          basis for all lengths.
        </li>
        <li>
          <a href="raster2.css?v={{version}}">raster2.css</a> is only 5 kB gzipped
        </li>
      </ul>
    </r-cell>

    <r-cell span=3.. class="ruler only-large-screen"></r-cell>

    <r-cell span=3.. span-s=row class="h2" id="custom-css">
      Customize raster.grid.css
    </r-cell>

    <r-cell span=3-6 span-s=row>
      <p>
        <a href="raster.grid.css?v={{version}}">raster.grid.css</a>
        provides the minimal set of <code>&lt;r-grid&gt;</code> functionality.
        If you're looking for a complete framework,
        use <a href="raster2.css?v={{version}}">raster2.css</a>
        instead.
      </p>
    </r-cell>

    <r-cell span=1-2 span-s=row class="only-large-screen form" style="max-width:15rem">
      <label><r-grid columns=4>
        <r-cell span=1-2>Prefix:</r-cell>
        <r-cell span=3-4><input type="text" value="r-" name="tagPrefix" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Columns:</r-cell>
        <r-cell span=3-4><input type="number" value="8" min=2 max=30 name="maxColumns" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Default cols:</r-cell>
        <r-cell span=3-4><input type="number" value="4" min=1 max=30 name="defaultColumns" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Small window:</r-cell>
        <r-cell span=3-4><input type="number" value="600" step="100" min=0 max="10000" name="smallScreenWidth" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Large window:</r-cell>
        <r-cell span=3-4><input type="number" value="1600" step="100" min=0 max="10000" name="largeScreenWidth" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Grid attr:</r-cell>
        <r-cell span=3-4><input type="text" value="columns" name="colsAttr" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Cell attr:</r-cell>
        <r-cell span=3-4><input type="text" value="span" name="spanAttr" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Small suffix:</r-cell>
        <r-cell span=3-4><input type="text" value="-s" name="smallAttrSuffix" autocomplete="off"></r-cell>
      </r-grid></label>
      <label><r-grid columns=4>
        <r-cell span=1-2>Large suffix:</r-cell>
        <r-cell span=3-4><input type="text" value="-l" name="largeAttrSuffix" autocomplete="off"></r-cell>
      </r-grid></label>
      <label>
        <input type="checkbox" name="includeDebug" checked>
        <span>Include .debug</span>
      </label>
      <br>
      <p>
        This CSS generator is also available as a script:
        <a href="res/generate-grid.js">generate-grid.js</a>
      </p>
    </r-cell>

    <r-cell span="3.." span-s="row">
      <div class="code-area">
        <div class="overlay"></div>
        <textarea class="code" id="css-output" autocomplete="off" spellcheck="false" readonly></textarea>
      </div>
      <h3>Open source</h3>
      <p>
        Raster is an open-source project and the
        <a href="https://github.com/rsms/raster">source code is available on GitHub &rarr;</a>
      </p>
      <script src="res/generate-grid.js?v={{generate_grid_js_v}}"></script>
      <script>(function(){

let cssOutput = document.querySelector('#css-output')

let inputs = {
  tagPrefix: document.querySelector('input[name="tagPrefix"]'),

  // minColumns: document.querySelector('input[name="minColumns"]'),
  maxColumns: document.querySelector('input[name="maxColumns"]'),
  defaultColumns: document.querySelector('input[name="defaultColumns"]'),
  smallScreenWidth: document.querySelector('input[name="smallScreenWidth"]'),
  largeScreenWidth: document.querySelector('input[name="largeScreenWidth"]'),

  colsAttr: document.querySelector('input[name="colsAttr"]'),
  spanAttr: document.querySelector('input[name="spanAttr"]'),
  smallAttrSuffix: document.querySelector('input[name="smallAttrSuffix"]'),
  largeAttrSuffix: document.querySelector('input[name="largeAttrSuffix"]'),

  includeDebug: document.querySelector('input[name="includeDebug"]'),
}

let values = {
  tagPrefix:  'r-',

  // minColumns: parseInt(inputs.minColumns.value),
  maxColumns: parseInt(inputs.maxColumns.value),
  defaultColumns: parseInt(inputs.defaultColumns.value),
  smallScreenWidth: parseInt(inputs.smallScreenWidth.value),
  largeScreenWidth: parseInt(inputs.largeScreenWidth.value),

  spanAttrNormal: 'span',
  spanAttrSmall:  'span-s',
  spanAttrLarge:  'span-l',
  colsAttrNormal: 'columns',
  colsAttrSmall:  'columns-s',
  colsAttrLarge:  'columns-l',

  includeDebug: inputs.includeDebug.checked,
}

function bindNumberInput(name, onchange) {
  let input = inputs[name]
  let f = ev => {
    let v = parseInt(input.value)
    if (!isNaN(v) && values[name] != v) {
      values[name] = v
      if (onchange) {
        let v2 = onchange(v)
        if (v2 !== undefined && v2 != v) {
          values[name] = v2
          input.value = v2
        }
      }
      genCSS()
    }
  }
  input.addEventListener('input', f)
  input.addEventListener('change', f)
}

function updateColsAttr() {
  let attr = inputs.colsAttr.value
  values['colsAttrNormal'] = attr
  values['colsAttrSmall'] =  attr + inputs.smallAttrSuffix.value
  values['colsAttrLarge'] =  attr + inputs.largeAttrSuffix.value
  genCSS()
}

function updateSpanAttr() {
  let attr = inputs.spanAttr.value
  values['spanAttrNormal'] = attr
  values['spanAttrSmall'] =  attr + inputs.smallAttrSuffix.value
  values['spanAttrLarge'] =  attr + inputs.largeAttrSuffix.value
  genCSS()
}

function updateAttrs() {
  updateColsAttr()
  updateSpanAttr()
}

inputs.colsAttr.addEventListener('input', updateColsAttr)
inputs.colsAttr.addEventListener('change', updateColsAttr)
inputs.spanAttr.addEventListener('input', updateSpanAttr)
inputs.spanAttr.addEventListener('change', updateSpanAttr)
inputs.smallAttrSuffix.addEventListener('input', updateAttrs)
inputs.smallAttrSuffix.addEventListener('change', updateAttrs)
inputs.largeAttrSuffix.addEventListener('input', updateAttrs)
inputs.largeAttrSuffix.addEventListener('change', updateAttrs)

inputs.tagPrefix.addEventListener('input', ev => {
  values.tagPrefix = inputs.tagPrefix.value
  genCSS()
})

inputs.includeDebug.addEventListener('change', ev => {
  values.includeDebug = inputs.includeDebug.checked
  genCSS()
})

// bindNumberInput('minColumns', minColumns => {
//   minColumns = Math.min(Math.max(2, minColumns), 30)
//   if (minColumns > values.maxColumns) {
//     inputs.maxColumns.value = values.maxColumns = minColumns
//   }
//   return minColumns
// })

bindNumberInput('maxColumns', maxColumns => {
  maxColumns = Math.min(Math.max(2, maxColumns), 30)
  if (maxColumns < values.minColumns) {
    inputs.minColumns.value = values.minColumns = maxColumns
  }
  return maxColumns
})

bindNumberInput('defaultColumns', defaultColumns => {
  defaultColumns = Math.min(Math.max(1, defaultColumns), 30)
  if (defaultColumns > values.maxColumns) {
    return values.maxColumns
  }
  return defaultColumns
})

bindNumberInput('smallScreenWidth')
bindNumberInput('largeScreenWidth')


function genCSS() {
  let css = Raster.generateCSS(values)
  cssOutput.value = css
  // cssOutput.scrollTop = 0
  // cssOutput.scrollTo(0,0)
}

let cssOutputScrolled = false
cssOutput.addEventListener('scroll', ev => {
  if (!cssOutputScrolled && cssOutput.scrollTop > 0) {
    cssOutputScrolled = true
    cssOutput.classList.add('scrolled')
  } else if (cssOutputScrolled && cssOutput.scrollTop <= 0) {
    cssOutputScrolled = false
    cssOutput.classList.remove('scrolled')
  }
}, {passive:true, capture:false})


cssOutput.addEventListener(
  'PointerEvent' in window ? 'pointerup' : 'click',
  ev => {
    cssOutput.select()
    // document.execCommand("copy")
  }
)

genCSS()

})()</script>
    </r-cell>

    <r-cell span=row class="ruler"></r-cell>

    <r-cell span=row class="h3" id="custom-css">
      <br>
      <a href="examples/">Explore the example gallery &rarr;</a>
      <br>
      <br>
    </r-cell>

    <r-cell span=row>
      <a href="https://rsms.me/" class="clean">@rsms</a>
    </r-cell>
  </r-grid>

<div id="smallScreenBeacon"></div>
<script>(function(){

// debug grid
let sg = document.querySelector('r-grid.demo')
sg.style.position = 'relative'
let dg = sg.cloneNode(false)
dg.classList.remove('demo')
dg.classList.add('debug-lines')
for (let col = 0; col < 8; col++) {
  let c = document.createElement('r-cell')
  c.innerHTML = '&nbsp;'
  dg.appendChild(c)
}
sg.appendChild(dg)

// smallScreenBeacon
let smallScreenBeacon = document.querySelector('#smallScreenBeacon')
function isSmallScreen() {
  return !!parseInt(window.getComputedStyle(smallScreenBeacon).width)
}


// example1 -- span-s simulator
let triggerEvent = 'PointerEvent' in window ? 'pointerdown' : 'click'
let exampleCount = 2
for (let i = 0; i < exampleCount; i++) {
  let example = document.querySelector(`#example${i+1}`)
  let exampleLabel1 = document.querySelector(`#example${i+1}-label1`)
  let exampleIsFlipped = false
  function updateExample1Label1() {
    let isSmall = exampleIsFlipped ? !isSmallScreen() : isSmallScreen()
    exampleLabel1.innerText = isSmall ? 'small' : 'large'
  }
  updateExample1Label1()
  let winResizeTimer = null
  window.addEventListener('resize', () => {
    clearTimeout(winResizeTimer)
    winResizeTimer = setTimeout(() => {
      updateExample1Label1()
    }, 200)
  })
  let flashTimer = null
  example.addEventListener(triggerEvent, ev => {
    exampleIsFlipped = !exampleIsFlipped
    updateExample1Label1()

    clearTimeout(flashTimer)
    exampleLabel1.classList.add('flash')
    flashTimer = setTimeout(() => {
      exampleLabel1.classList.remove('flash')
    }, 380)

    let colsS = example.getAttribute('columns-s')
    let colsM = example.getAttribute('columns')
    if (colsS !== null && colsM !== null) {
      example.setAttribute('columns', colsS)
      example.setAttribute('columns-s', colsM)
    }

    for (let i = 0; i < example.children.length; i++) {
      let c = example.children[i]
      // if (c.tagName != 'C') { continue }
      let spanS = c.getAttribute('span-s')
      let spanM = c.getAttribute('span')
      if (spanS !== null && spanM !== null) {
        c.setAttribute('span', spanS)
        c.setAttribute('span-s', spanM)
      }
    }
  })
}


})()</script>
{% include analytics.html %}
</body>
</html>
